/*****************************************************************
Mix3D WebGL Game Engine
Copyright (c) fantasy ( fantasy.x2x@gmail.com )
Listens:
Distributed under the Boost Software License, Version 1.0.
http://www.boost.org/LICENSE_1_0.txt
 ****************************************************************/
/**
 * @Desc    : OpenGLES2 renderable
 * @Author  : fantasy(fantasy.x2x@gmail.com)
 */
//////////////////////////////////////////////////////////////////
if(typeof(Mix3D) === 'undefined')
{
  Mix3D = {};
};
(function(Mix3D){
//////////////////////////////////////////////////////////////////
Mix3D.GLGeoBuffer = function(gl, geometry)
{
  this.gl = gl;
  this.geo = geometry;
  this.renderBuffers = []; //{_glVtxBuffers,_glMvaBuffers,_glIdxBuffer,_glLinesBuffer}
};

Mix3D.GLGeoBuffer.prototype.constructor = Mix3D.GLGeoBuffer;

Mix3D.GLGeoBuffer.prototype.destroy = function()
{
  var item, subGeo;
  var groups = this.geo.groups;
  if(groups)
  {
    for( var matIdx in groups )
    {
      subGeo = geo.groups[matIdx];
      for( item in subGeo._glVtxBuffers )
      {
        this.gl.deleteBuffer(subGeo._glVtxBuffers[item]);
      }
      subGeo._glVtxBuffers = undefined;
      if(subGeo._glMvaBuffers)
      {
        for( item in subGeo._glMvaBuffers )
        {
          this.gl.deleteBuffer(subGeo._glMvaBuffers[item]);
        }
        subGeo._glMvaBuffers = undefined;
      }
      if(subGeo._glIdxBuffers)
      {
        this.gl.deleteBuffer( subGeo._glIdxBuffers );
      }
      subGeo._glIdxBuffers = undefined;
      if(subGeo._glLinesBuffers)
      {
        this.gl.deleteBuffer( subGeo._glLinesBuffers );
      }
      subGeo._glLinesBuffers = undefined;
    }
  }
  else
  {
    for( item in geo._glVtxBuffers )
    {
      this.gl.deleteBuffer(geo._glVtxBuffers[item]);
    }
    geo._glVtxBuffers = undefined;
    if(geo._glMvaBuffers)
    {
      for( item in geo._glMvaBuffers )
      {
        this.gl.deleteBuffer(geo._glMvaBuffers[item]);
      }
      geo._glMvaBuffers = undefined;
    }
    if(geo._glIdxBuffer)
    {
      this.gl.deleteBuffer( geo._glIdxBuffer );
    }
    geo._glIdxBuffer = undefined;
    if(geo._glLinesBuffer)
    {
      this.gl.deleteBuffer( geo._glLinesBuffer );
    }
    geo._glLinesBuffer = undefined;
  }
};

Mix3D.GLGeoBuffer.prototype.createBuffers = function()
{
  this.updateBuffers();
};

function updateAttrBuffers( va, glBuffers )
{
  var buffer, glBuffer, item;
  if(!glBuffers)glBuffers={};
  
  for( item in va.buffers )
  {
    buffer = va.buffers[item].buffer;
    
    if(!buffer.isDirty)continue;

    glBuffer = glBuffers[item];
    if(!glBuffer)
    {
      glBuffer = this.gl.createBuffer();
      glBuffer._ElementSize = buffer.elementSize;
      glBuffers[item] = glBuffer;
    }
    this.gl.bindBuffer( this.gl.ARRAY_BUFFER, glBuffer );
	  this.gl.bufferData( this.gl.ARRAY_BUFFER, buffer.FA, this.gl.DYNAMIC_DRAW );///STATIC_DRAW
    buffer.isDirty = false;
  }
};

Mix3D.GLGeoBuffer.prototype.updateBuffers = function( material )
{
  var geo = this.geo;
  var groups = geo.groups;
  var subGeo, buffer, item;
  var buffer, glBuffer;
  var renderBuffer;
  if(groups)
  {
    geo.updateGroupMVA(material);
    for( var matIdx in groups )
    {
      subGeo = groups[matIdx];
      renderBuffer = subGeo.renderBuffer;
      
      //update vertex Buffer
      if(!renderBuffer)
      {
        renderBuffer = {};
        subGeo.renderBuffer = renderBuffer;
        this.renderBuffers.push(renderBuffer);
      }
      if(!renderBuffer._glVtxBuffers)
      {
        renderBuffer._glVtxBuffers={};
      }
      updateAttrBuffers(subGeo.vertices, renderBuffer._glVtxBuffers);
      
      //mva
      mva = subGeo.getMVA(matIdx !== -1?geo.materials[matIdx]:material);
      if(mva)
      {
        if(!mva._glBuffer)
        {
          mva._glBuffer = {};
        }
        
        renderBuffer._glMvaBuffers=mva._glBuffer;
        
        updateAttrBuffers(mva.va, renderBuffer._glMvaBuffers);
      }
      //indices
      if(!renderBuffer._glIdxBuffer)
      {
        glBuffer = this.gl.createBuffer();
        renderBuffer._glIdxBuffer = glBuffer;
        renderBuffer._triangleIdxCount = subGeo.indicesBuffer.FA.length;
        
        this.gl.bindBuffer( this.gl.ARRAY_BUFFER, glBuffer );
	      this.gl.bufferData( this.gl.ARRAY_BUFFER, subGeo.indicesBuffer.FA, this.gl.DYNAMIC_DRAW );///STATIC_DRAW
      }
      //lines
      if(!renderBuffer._glLinesBuffer)
      {
        glBuffer = this.gl.createBuffer();
        renderBuffer._glLinesBuffer = glBuffer;
        renderBuffer._lineIdxCount = subGeo.linesBuffer.FA.length;
        
        this.gl.bindBuffer( this.gl.ARRAY_BUFFER, glBuffer );
	      this.gl.bufferData( this.gl.ARRAY_BUFFER, subGeo.linesBuffer.FA, this.gl.DYNAMIC_DRAW );///STATIC_DRAW
      }
    }
  }
  else
  {
    renderBuffer = geo.renderBuffer;
    if(!renderBuffer)
    {
      renderBuffer = {};
      geo.renderBuffer=renderBuffer;
      this.renderBuffers.push(renderBuffer);
    }
    //va
    if(!renderBuffer._glVtxBuffers)
    {
      renderBuffer._glVtxBuffers = {};
    }
    updateAttrBuffers(geo.vertices, renderBuffer._glVtxBuffers);
    
    //mva
    mva = geo.getMVA(material);
    if(mva)
    {
      if(!mva._glBuffer)
      {
        mva._glBuffer = {};
      }
        
      renderBuffer._glMvaBuffers=mva._glBuffer;
      updateAttrBuffers(mva.va, renderBuffer._glMvaBuffers);
    }
    //indices
    if(geo.faces.getFaceNum()>0 && !renderBuffer._glIdxBuffer)
    {
      glBuffer = this.gl.createBuffer();
      renderBuffer._glIdxBuffer = glBuffer;
      renderBuffer._triangleIdxCount = geo.faces.indices.FA.length;
      renderBuffer._lineIdxCount = geo.faces.lines.FA.length;
        
      this.gl.bindBuffer( this.gl.ARRAY_BUFFER, glBuffer );
	    this.gl.bufferData( this.gl.ARRAY_BUFFER, geo.faces.indices.FA, this.gl.DYNAMIC_DRAW );///STATIC_DRAW
      
      //lines
      glBuffer = this.gl.createBuffer();
      renderBuffer._glLinesBuffer = glBuffer;
        
      this.gl.bindBuffer( this.gl.ARRAY_BUFFER, glBuffer );
	    this.gl.bufferData( this.gl.ARRAY_BUFFER, geo.faces.lines.FA, this.gl.DYNAMIC_DRAW );///STATIC_DRAW
    }
  }
};
//////////////////////////////////////////////////////////////////
//
//  GLRenderable
//
//////////////////////////////////////////////////////////////////
Mix3D.GLRenderable = function(gl, renderable)
{
  this.gl = gl;
  this.renderable = renderable;
  this.modelViewMatrix = new Mix3D.Matrix4();
  this.normalMatrix = new Mix3D.Matrix4();
   
  
  this.objectRenderBuffers = [];
  
  var geo = this.renderable.geometry;
  if(!geo._GLBuffer)
  {
    geo._GLBuffer = new Mix3D.GLGeoBuffer(gl, geo);
    geo._GLBuffer.createBuffers();
  }
  this.glGeo = geo._GLBuffer;
  
  var geoRenderBuffers = this.glGeo.renderBuffers;
  for(var i=0, len = geoRenderBuffers.length; i<len; ++i)
  {
  }
  
};
Mix3D.GLRenderable.prototype.constructor = Mix3D.GLRenderable;

Mix3D.GLRenderable.prototype.destroy = function()
{
  delete this.modelViewMatrix;
	delete this.normalMatrix;
	if(this.renderable.geometry._GLBuffer)
	{
	  this.renderable.geometry._GLBuffer.destroy();
	  delete this.renderable.geometry._GLBuffer;
	}
};

Mix3D.GLRenderable.prototype.update = function(camera)
{
  this.modelViewMatrix.mul(camera.getInvTransformMatrix(), this.renderable.worldTransform.getTransformMatrix());
  this.normalMatrix.inverseFrom(this.modelViewMatrix).transpose();
};

//////////////////////////////////////////////////////////////////
})(Mix3D);// end of function(Mix3D)